/**
 * <strong>抽象工厂是一种创建型设计模式，它能创建一系列相关的对象，而无需指定其具体类。<br>
 * 抽象工厂定义了用于创建不同产品的接口，但将实际的创建工作留给了具体工厂类。每个工厂类型都对应一个特定的产品变体。<br>
 * 在创建产品时，客户端代码调用的是工厂对象的构建方法，而不是直接调用构造函数（<code>new</code>操作符）。由于一个工厂对应一种产品变体，因此它创建的所有产品都可相互兼容。<br>
 * 客户端代码仅通过其抽象接口与工厂和产品进行交互。该接口允许同一客户端代码与不同产品进行交互。你只需创建一个具体工厂类并将其传递给客户端代码即可。<br>
 * <br>
 * 在 Java 中使用模式</strong><br>
 * 使用示例：抽象工厂模式在 Java 代码中很常见。许多框架和程序库会将它作为扩展和自定义其标准组件的一种方式。<br>
 * 以下是来自核心 Java 程序库的一些示例：<br>
 * {@link javax.xml.parsers.DocumentBuilderFactory#newInstance()}<br>
 * {@link javax.xml.transform.TransformerFactory#newInstance()}<br>
 * {@link javax.xml.xpath.XPathFactory#newInstance()}<br>
 * 识别方法：我们可以通过方法来识别该模式——其会返回一个工厂对象。接下来，工厂将被用于创建特定的子组件。<br>
 * <br>
 * <strong>跨平台 GUI 组件系列及其创建方式</strong><br>
 * 在本例中，按钮和复选框将被作为产品。它们有两个变体：macOS 版和 Windows 版。<br>
 * 抽象工厂定义了用于创建按钮和复选框的接口。而两个具体工厂都会返回同一变体的两个产品。<br>
 * 客户端代码使用抽象接口与工厂和产品进行交互。同样的代码能与依赖于不同工厂对象类型的多种产品变体进行交互。<br>
 * <br>
 * <strong>抽象工厂模式适合应用场景</strong><br>
 * 场景：如果代码需要与多个不同系列的相关产品交互，但是由于无法提前获取相关信息，或者出于对未来扩展性的考虑，你不希望代码基于产品的具体类进行构建，在这种情况下，你可以使用抽象工厂。<br>
 * 解决：抽象工厂为你提供了一个接口，可用于创建每个系列产品的对象。只要代码通过该接口创建对象，那么你就不会生成与应用程序已生成的产品类型不一致的产品。<br>
 * <ul>
 *     <li>如果你有一个基于一组抽象方法的类，且其主要功能因此变得不明确，那么在这种情况下可以考虑使用抽象工厂模式。</li>
 *     <li>在设计良好的程序中，每个类仅负责一件事。如果一个类与多种类型产品交互，就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。</li>
 * </ul>
 * <strong>实现方式</strong><br>
 * <ol>
 *     <li>以不同的产品类型与产品变体为维度绘制矩阵。</li>
 *     <li>为所有产品声明抽象产品接口。然后让所有具体产品类实现这些接口。</li>
 *     <li>声明抽象工厂接口，并且在接口中为所有抽象产品提供一组构建方法。</li>
 *     <li>为每种产品变体实现一个具体工厂类。</li>
 *     <li>在应用程序中开发初始化代码。该代码根据应用程序配置或当前环境，对特定具体工厂类进行初始化。然后将该工厂对象传递给所有需要创建产品的类。</li>
 *     <li>找出代码中所有对产品构造函数的直接调用，将其替换为对工厂对象中相应构建方法的调用。</li>
 * </ol>
 * <strong>抽象工厂模式优缺点</strong>
 * <br>
 * 优点：
 * <ol>
 *     <li>你可以确保同一工厂生成的产品相互匹配。</li>
 *     <li>你可以避免客户端和具体产品代码的耦合。</li>
 *     <li>单一职责原则。你可以将产品生成代码抽取到同一位置，使得代码易于维护。</li>
 *     <li>开闭原则。向应用程序中引入新产品变体时，你无需修改客户端代码。</li>
 * </ol>
 * 缺点：
 * <br>
 * <ol>
 *     <li>由于采用该模式需要向应用中引入众多接口和类，代码可能会比之前更加复杂。</li>
 * </ol>
 * <strong>与其他模式的关系</strong>
 * <ul>
 *     <li>在许多设计工作的初期都会使用工厂方法模式（较为简单，而且可以更方便地通过子类进行定制），随后演化为使用抽象工厂模式、原型模式或生成器模式（更灵活但更加复杂）。</li>
 *     <li>生成器重点关注如何分步生成复杂对象。抽象工厂专门用于生产一系列相关对象。抽象工厂会马上返回产品，生成器则允许你在获取产品前执行一些额外构造步骤。</li>
 *     <li>抽象工厂模式通常基于一组工厂方法，但你也可以使用原型模式来生成这些类的方法。</li>
 *     <li>当只需对客户端代码隐藏子系统创建对象的方式时，你可以使用抽象工厂来代替外观模式。</li>
 *     <li>你可以将抽象工厂和桥接模式搭配使用。如果由桥接定义的抽象只能与特定实现合作，这一模式搭配就非常有用。在这种情况下，抽象工厂可以对这些关系进行封装，并且对客户端代码隐藏其复杂性。</li>
 *     <li>抽象工厂、生成器和原型都可以用单例模式来实现。</li>
 * </ul>
 */
package com.cg.design.depthdesign.abstractfactory;